using System;
using System.IO;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using System.Timers;
using Admaco.Data;
using Admaco.Logic;
using System.Drawing;
using System.Configuration;

using LumenWorks.Framework.IO.Csv;

[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.xml",
  ConfigFileExtension = "config", Watch = false)]

namespace Admaco.Logic
{
    /// <summary>
    /// Servicio de ejecucion de procesos en segundo plano
    /// </summary>
    public partial class EjecucionAnalisis : ServiceBase
    {
        private static log4net.ILog log = log4net.LogManager.GetLogger("ejecucionAnalisis.Logging");

        /// <summary>
        /// Ejecucion de analisis Conexiones Laterales
        /// </summary>
        private static MConexionesLaterales conexionesLaterales;

        /// <summary>
        /// Ejecucion de analisis Maximum Likelihood
        /// </summary>
        private static MMaximumLikelihood maximumLikelihood;

        /// <summary>
        /// Ejecucion de analisis PCA estadistico
        /// </summary>
        private static MPCAEstadistico pcaEstadistico;

        /// <summary>
        /// Ejecucion de analisis PCA Neuronal
        /// </summary>
        private static MPCANeuronal pcaNeuronal;

        /// <summary>
        /// Intervalo de ejecucion del servicio
        /// </summary>
        private static int intervalo = 2000;
        private static Timer temporizador = new Timer();                        

        /// <summary>
        /// Inicializa el servicio
        /// </summary>
        public EjecucionAnalisis()
        {
            conexionesLaterales = MConexionesLaterales.Instance;
            maximumLikelihood = MMaximumLikelihood.Instance;
            pcaEstadistico = MPCAEstadistico.Instance;
            pcaNeuronal = MPCANeuronal.Instance;

            InitializeComponent();      
        }

        /// <summary>
        /// Inicializa el timer al arrancar el servicio
        /// </summary>
        protected override void OnStart(string[] args)
        {
            temporizador.Elapsed += new ElapsedEventHandler(OnTimedEvent);
            temporizador.Interval = intervalo;
            temporizador.Enabled = true;
            temporizador.Start();            
        }            
        
        /// <summary>
        /// Para el timer al parar el servicio
        /// </summary>
        protected override void OnStop()
        {
            temporizador.Stop();
        }

        /// <summary>
        /// Ejecuta el analisis pendiente en la cola
        /// </summary>
        private static void OnTimedEvent(object source, ElapsedEventArgs e)
        {
            AppSettingsReader appReader = new AppSettingsReader();
            String stringType = "";
            String dataDirectory = (String)appReader.GetValue("dataDirectory", stringType.GetType());

            try
            {
                // Desactivo temporizador mientras se ejecuta el analisis pendiente
                temporizador.Enabled = false;

                // Obtengo el analisis pendiente de ejecucion
                Analisis analisis = new Analisis();
                ArrayList analisisArray = analisis.getByEstado(Estado.programado);
                if (analisisArray.Count > 0)
                {
                    Analisis ana = (Analisis)analisisArray[0];

                    if (log.IsInfoEnabled) log.Info("Ejecutando analisis: " + ana.Fichero.FicheroClases + " " + ana.Fichero.FicheroDatos + " " + ana.TipoAnalisis.Nombre);

                    // Actualizo el estado a ejecutando
                    ana.Estado.get(Estado.ejecutando);
                    ana.FechaInicio = DateTime.Now;
                    ana.save();
                    
                    String ficheroImagen = null;
                    String ficheroPesos = null;

                    // Selecciona todos los atributos del fichero
                    String ficheroSeleccion = Path.GetTempFileName();

                    using (StreamWriter streamWriter = new StreamWriter(ficheroSeleccion))
                    {

                        using (CsvReader csv = new CsvReader(new StreamReader(ana.Fichero.FicheroDatos), true, ';'))
                        {
                            int fieldCount = csv.FieldCount;

                            String registroSeleccion;

                            while (csv.ReadNextRecord())
                            {
                                registroSeleccion = "";

                                for (int i = 0; i < fieldCount; i++)
                                {
                                    if (i != 0)
                                        registroSeleccion += ";";

                                    registroSeleccion += csv[i];
                                }

                                streamWriter.WriteLine(registroSeleccion);
                            }
                        }
                    }


                    // Ejecuto el proceso
                    switch (ana.TipoAnalisis.IdTipoAnalisis)
                    {
                        case TipoAnalisis.pcaEstadistico:
                            pcaEstadistico.ejecutar(ficheroSeleccion, ana.Fichero.FicheroClases, dataDirectory + @"\", false);
                            ficheroImagen = dataDirectory + @"\PCAEstadistico.jpg";
                            ficheroPesos = dataDirectory + @"\PCAEstadisticoPesos.txt";
                            break;

                        case TipoAnalisis.pcaNeuronal:
                            TPCANeuronal datosNeuronal = new TPCANeuronal();
                            datosNeuronal.get(ana.IdAnalisis);
                            pcaNeuronal.ejecutar(datosNeuronal.NumeroNeuronas, datosNeuronal.CoefiAprendizaje,datosNeuronal.NumIteraciones,
                                ficheroSeleccion, ana.Fichero.FicheroClases, dataDirectory + @"\", false);
                            ficheroImagen = dataDirectory + @"\PCANeuronal.jpg";
                            ficheroPesos = dataDirectory + @"\PCANeuronalPesos.txt";                                
                            break;

                        case TipoAnalisis.conexionesLaterales:
                            TConexionesLaterales datosConexiones = new TConexionesLaterales();
                            datosConexiones.get(ana.IdAnalisis);
                            conexionesLaterales.ejecutar(datosConexiones.NumeroNeuronas, datosConexiones.CoefiAprendizaje,datosConexiones.P,
                                datosConexiones.Tau, datosConexiones.NumIteraciones, ficheroSeleccion, ana.Fichero.FicheroClases, dataDirectory + @"\", false);    
                            ficheroImagen = dataDirectory + @"\ConexionesLaterales.jpg";
                            ficheroPesos = dataDirectory + @"\ConexionesLateralesPesos.txt";                                                                                            
                            break;

                        case TipoAnalisis.maximumLikelihood:
                            TMaximumLikelihood datosMaximum = new TMaximumLikelihood();
                            datosMaximum.get(ana.IdAnalisis);
                            maximumLikelihood.ejecutar(datosMaximum.NumeroNeuronas, datosMaximum.CoefiAprendizaje, datosMaximum.P,
                                datosMaximum.NumIteraciones, ficheroSeleccion, ana.Fichero.FicheroClases, dataDirectory + @"\", false);
                            ficheroImagen = dataDirectory + @"\MaximumLikelihood.jpg";
                            ficheroPesos = dataDirectory + @"\MaximumLikelihoodPesos.txt";                                                                                       
                            break;
                    }

                    // Asigno la imagen resultado al analisis
                    using (FileStream imageStream = new FileStream(ficheroImagen, FileMode.Open, FileAccess.Read))
                    {
                        ana.Imagen = System.Drawing.Image.FromStream(imageStream);

                        using (StreamReader pesosStream = new StreamReader(ficheroPesos))
                        {
                            ana.FicheroMatrizPesos = pesosStream.ReadToEnd();
                        }
                    
                        // Actualizo el estado a finalizado
                        ana.Estado.get(Estado.finalizado);
                        ana.FechaFin = DateTime.Now;
                        ana.save();
                    }

                    File.Delete(ficheroImagen);
                    File.Delete(ficheroPesos);
                }
            }
            catch (Exception ex)
            {
                if (log.IsErrorEnabled) log.Error(ex);
                
                using (StreamWriter buffer = File.AppendText(dataDirectory + @"\error.txt"))
                {
                    buffer.Write(ex);
                }
            }
           
            // Habilito el temporizador
            temporizador.Enabled = true;           

        }
    }
}